/*
 * AnyOption 1.3
 *
 * kishan at hackorama dot com  www.hackorama.com JULY 2001
 *
 * + Acts as a common facade class for reading
 *   commandline options as well as options from
 *   an optionfile with delimited type value pairs
 *
 * + Handles the POSIX style single character options ( -w )
 *   as well as the newer GNU long options ( --width )
 *
 * + The option file assumes the traditional format of
 *   first character based comment lines and type value
 *   pairs with a delimiter , and flags which are not pairs
 *
 *  	# this is a coment
 *  	# next line is an option value pair
 *  	width : 100
 *     	# next line is a flag
 *      noimages
 *
 * + Supports printing out Help and Usage
 *
 * + Why not just use getopt() ?
 *
 *   getopt() Its a POSIX standard not part of ANSI-C.
 *   So it may not be available on platforms like Windows.
 *
 * + Why it is so long ?
 *
 *   The actual code which does command line parsing
 *   and option file parsing are done in  few methods.
 *   Most of the extra code are for providing a flexible
 *   common public interface to both a resourcefile and
 *   and command line supporting POSIX style and
 *   GNU long option as well as mixing of both.
 *
 * + Please see "anyoption.h" for public method descriptions
 *
 */

/* Updated Auguest 2004
 * Fix from  Michael D Peters (mpeters at sandia.gov)
 * to remove static local variables, allowing multiple instantiations
 * of the reader (for using multiple configuration files).  There is
 * an error in the destructor when using multiple instances, so you
 * cannot delete your objects (it will crash), but not calling the
 * destructor only introduces a small memory leak, so I
 * have not bothered tracking it down.
 *
 * Also updated to use modern C++ style headers, rather than
 * depricated iostream.h (it was causing my compiler problems)
 */

/*
 * Updated September 2006
 * Fix from Boyan Asenov for a bug in mixing up option indexes
 * leading to exception when mixing different options types
 */

#include <sys/ioctl.h>

#include "anyoption.h"

AnyOption::AnyOption()
{
  init();
}

AnyOption::AnyOption(const string& usage_prefix)
{
  init();
  setVerbose(); /* print warnings about unknown options */
  autoUsagePrint(true); /* print usage for bad options */
  addUsage(usage_prefix);
  addUsage("Allowed Options");
}

AnyOption::AnyOption(int maxopt)
{
  init( maxopt , maxopt );
}

AnyOption::AnyOption(int maxopt, int maxcharopt)
{
  init( maxopt , maxcharopt );
}

AnyOption::~AnyOption()
{
  if( mem_allocated )
    cleanup();
}

void
AnyOption::init()
{
  init( DEFAULT_MAXOPTS , DEFAULT_MAXOPTS );
}

void
AnyOption::init(int maxopt, int maxcharopt )
{
  max_options 	= maxopt;
  max_char_options = maxcharopt;
  usage_lines	= 0 ;
  argc 		= 0;
  argv 		= NULL;
  posix_style	= true;
  verbose 	= false;
  filename 	= NULL;
  appname 	= NULL;
  option_counter 	= 0;
  optchar_counter	= 0;
  new_argv 	= NULL;
  new_argc 	= 0 ;
  max_legal_args 	= 0 ;
  command_set 	= false;
  file_set 	= false;
  g_value_counter = 0;
  mem_allocated 	= false;
  command_set 	= false;
  file_set	= false;
  opt_prefix_char     = '-';
  file_delimiter_char = ':';
  file_comment_char   = '#';
  equalsign 	= '=';
  comment       = '#' ;
  delimiter     = ':' ;
  endofline     = '\n';
  whitespace    = ' ' ;
  nullterminate = '\0';
  set = false;
  once = true;
  hasoptions = false;
  autousage = false;
  
  strcpy( long_opt_prefix , "--" );
  
  if( alloc() == false ){
    cout << endl << "OPTIONS ERROR : Failed allocating memory" ;
    cout << endl ;
    cout << "Exiting." << endl;
    exit (0);
  }
  
  struct winsize ws;
  ioctl(0,TIOCGWINSZ,&ws);
  terminal_width = (ws.ws_col==0) ? 80 : ws.ws_col;
}

bool
AnyOption::alloc()
{
  int i = 0 ;
  int size = 0 ;
  
  if( mem_allocated )
    return true;
  
  size = (max_options+1) * sizeof(const char*);
  options.clear();
  optiontype = (int*) malloc( (max_options+1)*sizeof(int) );
  optionindex = (int*) malloc( (max_options+1)*sizeof(int) );
  if( optiontype == NULL || optionindex == NULL )
    return false;
  else
    mem_allocated  = true;
  for( i = 0 ; i < max_options ; i++ ){
    optiontype[i] = 0 ;
    optionindex[i] = -1 ;
  }
  optionchars = (char*) malloc( (max_char_options+1)*sizeof(char) );
  optchartype = (int*) malloc( (max_char_options+1)*sizeof(int) );
  optcharindex = (int*) malloc( (max_char_options+1)*sizeof(int) );
  if( optionchars == NULL ||
     optchartype == NULL ||
     optcharindex == NULL )
  {
    mem_allocated = false;
    return false;
  }
  for( i = 0 ; i < max_char_options ; i++ ){
    optionchars[i] = '0';
    optchartype[i] = 0 ;
    optcharindex[i] = -1 ;
  }
  
  return true;
}

bool
AnyOption::doubleOptStorage()
{
  optiontype = (int*) realloc(  optiontype ,
                              ((2 * max_options)+1)* sizeof(int) );
  optionindex = (int*) realloc(  optionindex,
                               ((2 * max_options)+1) * sizeof(int) );
  if( optiontype == NULL || optionindex == NULL )
    return false;
  /* init new storage */
  for( int i = max_options ; i < 2*max_options ; i++ ){
    optiontype[i] = 0 ;
    optionindex[i] = -1 ;
  }
  max_options = 2 * max_options ;
  return true;
}

bool
AnyOption::doubleCharStorage()
{
  optionchars = (char*) realloc( optionchars,
                                ((2*max_char_options)+1)*sizeof(char) );
  optchartype = (int*) realloc( optchartype,
                               ((2*max_char_options)+1)*sizeof(int) );
  optcharindex = (int*) realloc( optcharindex,
                                ((2*max_char_options)+1)*sizeof(int) );
  if( optionchars == NULL ||
     optchartype == NULL ||
     optcharindex == NULL )
    return false;
  /* init new storage */
  for( int i = max_char_options ; i < 2*max_char_options ; i++ ){
    optionchars[i] = '0';
    optchartype[i] = 0 ;
    optcharindex[i] = -1 ;
  }
  max_char_options = 2 * max_char_options;
  return true;
}


void
AnyOption::cleanup()
{
  free (optiontype);
  free (optionindex);
  free (optionchars);
  free (optchartype);
  free (optcharindex);
  
  if( new_argv != NULL )
    free (new_argv);
}

void
AnyOption::setCommandPrefixChar( char _prefix )
{
  opt_prefix_char = _prefix;
}

void
AnyOption::setCommandLongPrefix( char *_prefix )
{
  if( strlen( _prefix ) > MAX_LONG_PREFIX_LENGTH ){
    *( _prefix + MAX_LONG_PREFIX_LENGTH ) = '\0';
  }
  
  strcpy (long_opt_prefix,  _prefix);
}

void
AnyOption::setFileCommentChar( char _comment )
{
  file_delimiter_char = _comment;
}


void
AnyOption::setFileDelimiterChar( char _delimiter )
{
  file_comment_char = _delimiter ;
}

bool
AnyOption::CommandSet()
{
  return( command_set );
}

bool
AnyOption::FileSet()
{
  return( file_set );
}

void
AnyOption::noPOSIX()
{
  posix_style = false;
}

bool
AnyOption::POSIX()
{
  return posix_style;
}


void
AnyOption::setVerbose()
{
  verbose = true ;
}

void
AnyOption::printVerbose()
{
  if( verbose )
    cout << endl  ;
}
void
AnyOption::printVerbose( const char *msg )
{
  if( verbose )
    cout << msg  ;
}

void
AnyOption::printVerbose( char *msg )
{
  if( verbose )
    cout << msg  ;
}

void
AnyOption::printVerbose( char ch )
{
  if( verbose )
    cout << ch ;
}

bool
AnyOption::hasOptions()
{
  return hasoptions;
}

void
AnyOption::autoUsagePrint(bool _autousage)
{
  autousage = _autousage;
}

void
AnyOption::useCommandArgs( int _argc, char** _argv )
{
  argc = _argc;
  argv = _argv;
  command_set = true;
  appname = argv[0];
  if(argc > 1) hasoptions = true;
}

void
AnyOption::useFilename( const char *_filename )
{
  filename = _filename;
  file_set = true;
}

/*
 * set methods for options
 */

void
AnyOption::setCommandOption( const char *opt )
{
  addOption( opt , COMMAND_OPT );
  g_value_counter++;
}

void
AnyOption::setCommandOption( char opt )
{
  addOption( opt , COMMAND_OPT );
  g_value_counter++;
}

void
AnyOption::setCommandOption( const char *opt , char optchar )
{
  addOption( opt , COMMAND_OPT );
  addOption( optchar , COMMAND_OPT );
  g_value_counter++;
}

void
AnyOption::setCommandFlag( const char *opt )
{
  addOption( opt , COMMAND_FLAG );
  g_value_counter++;
}

void
AnyOption::setCommandFlag( char opt )
{
  addOption( opt , COMMAND_FLAG );
  g_value_counter++;
}

void
AnyOption::setCommandFlag( const char *opt , char optchar )
{
  addOption( opt , COMMAND_FLAG );
  addOption( optchar , COMMAND_FLAG );
  g_value_counter++;
}

void
AnyOption::setFileOption( const char *opt )
{
  addOption( opt , FILE_OPT );
  g_value_counter++;
}

void
AnyOption::setFileOption( char opt )
{
  addOption( opt , FILE_OPT );
  g_value_counter++;
}

void
AnyOption::setFileOption( const char *opt , char optchar )
{
  addOption( opt , FILE_OPT );
  addOption( optchar, FILE_OPT  );
  g_value_counter++;
}

void
AnyOption::setFileFlag( const char *opt )
{
  addOption( opt , FILE_FLAG );
  g_value_counter++;
}

void
AnyOption::setFileFlag( char opt )
{
  addOption( opt , FILE_FLAG );
  g_value_counter++;
}

void
AnyOption::setFileFlag( const char *opt , char optchar )
{
  addOption( opt , FILE_FLAG );
  addOption( optchar , FILE_FLAG );
  g_value_counter++;
}

void
AnyOption::setOption( const char *opt )
{
  addOption( opt , COMMON_OPT );
  g_value_counter++;
}

void
AnyOption::setOption( char opt )
{
  addOption( opt , COMMON_OPT );
  g_value_counter++;
}

void
AnyOption::setOption( const char *opt , char optchar )
{
  addOption( opt , COMMON_OPT );
  addOption( optchar , COMMON_OPT );
  g_value_counter++;
}

void
AnyOption::setFlag( const char *opt )
{
  addOption( opt , COMMON_FLAG );
  g_value_counter++;
}

void
AnyOption::setFlag( const char opt )
{
  addOption( opt , COMMON_FLAG );
  g_value_counter++;
}

void
AnyOption::setFlag( const char *opt , char optchar )
{
  addOption( opt , COMMON_FLAG );
  addOption( optchar , COMMON_FLAG );
  g_value_counter++;
}

void
AnyOption::addOption( const string opt, int type )
{
  if( option_counter >= max_options ){
    if( doubleOptStorage() == false ){
      addOptionError( opt );
      return;
    }
  }
  options.push_back(opt);
  optiontype[ option_counter ] =  type ;
  optionindex[ option_counter ] = g_value_counter;
  option_counter++;
}

void
AnyOption::addOption( char opt, int type )
{
  if( !POSIX() ){
    printVerbose("Ignoring the option character \"");
    printVerbose(  opt );
    printVerbose( "\" ( POSIX options are turned off )" );
    printVerbose();
    return;
  }
  
  
  if( optchar_counter >= max_char_options ){
    if( doubleCharStorage() == false ){
      addOptionError( opt );
      return;
    }
  }
  optionchars[ optchar_counter ] =  opt ;
  optchartype[ optchar_counter ] =  type ;
  optcharindex[ optchar_counter ] = g_value_counter;
  optchar_counter++;
}

void
AnyOption::addOptionError( const string opt )
{
  cout << endl ;
  cout << "OPTIONS ERROR : Failed allocating extra memory " << endl ;
  cout << "While adding the option : \""<< opt << "\"" << endl;
  cout << "Exiting." << endl ;
  cout << endl ;
  exit(0);
}

void
AnyOption::addOptionError( char opt )
{
  cout << endl ;
  cout << "OPTIONS ERROR : Failed allocating extra memory " << endl ;
  cout << "While adding the option: \""<< opt << "\"" << endl;
  cout << "Exiting." << endl ;
  cout << endl ;
  exit(0);
}

void
AnyOption::processCommandArgs(int max_args)
{
  max_legal_args = max_args;
  processCommandArgs();
}

void
AnyOption::processCommandArgs( int _argc, char **_argv, int max_args )
{
  max_legal_args = max_args;
  processCommandArgs(  _argc, _argv );
}

void
AnyOption::processCommandArgs( int _argc, char **_argv )
{
  useCommandArgs( _argc, _argv );
  processCommandArgs();
}

void
AnyOption::processCommandArgs()
{
  if (!CommandSet())
    return;
  
  if (max_legal_args == 0)
    max_legal_args = argc;
  
  new_argv = (int*) malloc((max_legal_args + 1) * sizeof(int));
  
  /* ignore first argv */
  for (int i = 1; i < argc; i++)
  {
    /* long GNU option */
    if (argv[i][0] == long_opt_prefix[0] && argv[i][1] == long_opt_prefix[1])
    {
      int match_at = parseGNU(argv[i] + 2); /* skip -- */
      if (match_at >= 0 && i < argc - 1) /* found match */
        setValue(options[match_at], argv[++i]);
    }
    /* POSIX char */
    else if (argv[i][0] == opt_prefix_char)
    {
      if (POSIX())
      {
        char ch = parsePOSIX(argv[i] + 1);/* skip - */
        if (ch != '0' && i < argc - 1) /* matching char */
          setValue(ch, argv[++i]);
      }
      /* treat it as GNU option with a - */
      else
      {
        int match_at = parseGNU(argv[i] + 1); /* skip - */
        if (match_at >= 0 && i < argc - 1) /* found match */
          setValue(options[match_at], argv[++i]);
      }
    }
    /* not option but an argument keep index */
    else
    {
      if (new_argc < max_legal_args)
      {
        new_argv[new_argc] = i;
        new_argc++;
      }
      /* ignore extra arguments */
      else
      {
        printVerbose("Ignoring extra argument: ");
        printVerbose(argv[i]);
        printVerbose();
        printAutoUsage();
      }
    }
  }
}

char
AnyOption::parsePOSIX(char* arg)
{
  for (unsigned int i = 0; i < strlen(arg); i++)
  {
    char ch = arg[i];
    if (matchChar(ch))
    { /* keep matching flags till an option */
      /*if last char argv[++i] is the value */
      if (i == strlen(arg) - 1)
      {
        return ch;
      }
      else
      {/* else the rest of arg is the value */
        i++; /* skip any '=' and ' ' */
        while (arg[i] == whitespace || arg[i] == equalsign)
          i++;
        setValue(ch, arg + i);
        return '0';
      }
    }
  }
  return '0';
}

int
AnyOption::parseGNU(char *arg)
{
  int split_at = 0;
  /* if has a '=' sign get value */
  for (unsigned int i = 0; i < strlen(arg); i++)
  {
    if (arg[i] == equalsign)
    {
      split_at = i; /* store index */
      i = strlen(arg); /* get out of loop */
    }
  }
  if (split_at > 0)
  { /* it is an option value pair */
    char* tmp = (char*) malloc((split_at + 1) * sizeof(char));
    for (int i = 0; i < split_at; i++)
      tmp[i] = arg[i];
    tmp[split_at] = '\0';
    
    if (matchOpt(tmp) >= 0)
    {
      setValue(options[matchOpt(tmp)], arg + split_at + 1);
      free(tmp);
    }
    else
    {
      printVerbose("Unknown command argument option: ");
      printVerbose(arg);
      printVerbose();
      printAutoUsage();
      free(tmp);
      exit(-1);
      //return -1;
    }
  }
  else
  { /* regular options with no '=' sign  */
    return matchOpt(arg);
  }
  return -1;
}


int
AnyOption::matchOpt( char *opt )
{
  for( int i = 0 ; i < option_counter ; i++ ){
    if( options[i].compare(opt) == 0 ){
      if( optiontype[i] ==  COMMON_OPT ||
         optiontype[i] ==  COMMAND_OPT )
      { /* found option return index */
        return i;
      }else if( optiontype[i] == COMMON_FLAG ||
               optiontype[i] == COMMAND_FLAG )
      { /* found flag, set it */
        setFlagOn( opt );
        return -1;
      }
    }
  }
  printVerbose( "Unknown command argument option: " );
  printVerbose( opt  ) ;
  printVerbose( );
  printAutoUsage();
  exit(-1);
  //return  -1;
}
bool
AnyOption::matchChar( char c )
{
  for( int i = 0 ; i < optchar_counter ; i++ ){
    if( optionchars[i] == c ) { /* found match */
      if(optchartype[i] == COMMON_OPT ||
         optchartype[i] == COMMAND_OPT )
      { /* an option store and stop scanning */
        return true;
      }else if( optchartype[i] == COMMON_FLAG ||
               optchartype[i] == COMMAND_FLAG ) { /* a flag store and keep scanning */
        setFlagOn( c );
        return false;
      }
    }
  }
  printVerbose( "Unknown command argument option: " );
  printVerbose( c ) ;
  printVerbose( );
  printAutoUsage();
  exit(-1);
  //return false;
}

/*
 * public get methods
 */
string*
AnyOption::getValue( const string option )
{
  for( int i = 0 ; i < option_counter ; i++ )
    if( options[i].compare(option) == 0 )
      return (values.count(optionindex[i]) > 0) ? &values[ optionindex[i] ] : NULL;
  
  return NULL;
}

bool
AnyOption::getFlag( const string option )
{
  for( int i = 0 ; i < option_counter ; i++ )
    if( options[i].compare(option) == 0 )
      return findFlag( optionindex[i] );
  
  return false;
}

bool
AnyOption::isOptUsed( const string option )
{
  for( int i = 0 ; i < argc ; i++ )
    if( substitute(argv[i], "-", "") == option )
      return true;
  
  return false;
}

string*
AnyOption::getValue( char option )
{
  for( int i = 0 ; i < optchar_counter ; i++ )
    if( optionchars[i] == option )
      return (values.count(optcharindex[i]) > 0) ? &values[ optcharindex[i] ] : NULL;
  
  return NULL;
}

bool
AnyOption::getFlag( char option )
{
  for( int i = 0 ; i < optchar_counter ; i++ )
    if( optionchars[i] == option )
      return findFlag( optcharindex[i] );
  
  return false;
}

bool
AnyOption::isOptUsed( char option )
{
  for( int i = 0 ; i < argc ; i++ )
    if( substitute(argv[i], "-", "") == &option )
      return true;
  
  return false;
}

bool
AnyOption::findFlag( int index )
{
  return (values.count(index) && values[index].compare(TRUE_FLAG) == 0);
}

/*
 * private set methods
 */
bool
AnyOption::setValue( const string option , string value )
{
  for( int i = 0 ; i < option_counter ; i++ ){
    if( options[i].compare(option) == 0 ){
      if (values[ optionindex[i] ].size() > 0) values[ optionindex[i] ]+= "\n";
      values[ optionindex[i] ] += value;
      return true;
    }
  }
  return false;
}

bool
AnyOption::setFlagOn( const string option )
{
  return setValue(option, TRUE_FLAG);
}

bool
AnyOption::setValue( char option , string value )
{
  for( int i = 0 ; i < optchar_counter ; i++ ){
    if( optionchars[i] == option ){
      if (values[ optcharindex[i] ].size() > 0) values[ optcharindex[i] ]+= "\n";
      values[ optcharindex[i] ] += value;
      return true;
    }
  }
  return false;
}

bool
AnyOption::setFlagOn( char option )
{
  return setValue(option, TRUE_FLAG);
}


int
AnyOption::getArgc( )
{
  return new_argc;
}

char*
AnyOption::getArgv( int index )
{
  if( index < new_argc ){
    return ( argv[ new_argv[ index ] ] );
  }
  return NULL;
}

/* dotfile sub routines */

bool
AnyOption::processFile()
{
  if( !FileSet() )
    return false;
  return  ( consumeFile(readFile()) );
}

bool
AnyOption::processFile( const char *filename )
{
  useFilename(filename );
  return ( processFile() );
}

char*
AnyOption::readFile()
{
  return ( readFile(filename) );
}

/*
 * read the file contents to a character buffer
 */

char*
AnyOption::readFile( const char* fname )
{
  int length;
  char *buffer;
  ifstream is;
  is.open ( fname , ifstream::in );
  if( ! is.good() ){
    is.close();
    return NULL;
  }
  is.seekg (0, ios::end);
  length = is.tellg();
  is.seekg (0, ios::beg);
  buffer = (char*) malloc(length*sizeof(char));
  is.read (buffer,length);
  is.close();
  return buffer;
}

/*
 * scans a char* buffer for lines that does not
 * start with the specified comment character.
 */
bool
AnyOption::consumeFile( char *buffer )
{
  
  if( buffer == NULL )
    return false;
  
  char *cursor = buffer;/* preserve the ptr */
  char *pline = NULL ;
  int linelength = 0;
  bool newline = true;
  for( unsigned int i = 0 ; i < strlen( buffer ) ; i++ ){
    if( *cursor == endofline ) { /* end of line */
      if( pline != NULL ) /* valid line */
        processLine( pline, linelength );
      pline = NULL;
      newline = true;
    }else if( newline ){ /* start of line */
      newline = false;
      if( (*cursor != comment ) ){ /* not a comment */
        pline = cursor ;
        linelength = 0 ;
      }
    }
    cursor++; /* keep moving */
    linelength++;
  }
  free (buffer);
  return true;
}


/*
 *  find a valid type value pair separated by a delimiter
 *  character and pass it to valuePairs()
 *  any line which is not valid will be considered a value
 *  and will get passed on to justValue()
 *
 *  assuming delimiter is ':' the behaviour will be,
 *
 *  width:10    - valid pair valuePairs( width, 10 );
 *  width : 10  - valid pair valuepairs( width, 10 );
 *
 *  ::::        - not valid
 *  width       - not valid
 *  :10         - not valid
 *  width:      - not valid
 *  ::          - not valid
 *  :           - not valid
 *
 */

void
AnyOption::processLine( char *theline, int length  )
{
  bool found = false;
  char *pline = (char*) malloc( (length+1)*sizeof(char) );
  for( int i = 0 ; i < length ; i ++ )
    pline[i]= *(theline++);
  pline[length] = nullterminate;
  char *cursor = pline ; /* preserve the ptr */
  if( *cursor == delimiter || *(cursor+length-1) == delimiter ){
    justValue( pline );/* line with start/end delimiter */
  }else{
    for( int i = 1 ; i < length-1 && !found ; i++){/* delimiter */
      if( *cursor == delimiter ){
        *(cursor-1) = nullterminate; /* two strings */
        found = true;
        valuePairs( pline , cursor+1 );
      }
      cursor++;
    }
    cursor++;
    if( !found ) /* not a pair */
      justValue( pline );
  }
  free (pline);
}

void
AnyOption::valuePairs( char *type, string value )
{
  if ( chomp(type).size() == 1  ){ /* this is a char option */
    for( int i = 0 ; i < optchar_counter ; i++ ){
      if(  optionchars[i] == type[0]  ){ /* match */
        if( optchartype[i] == COMMON_OPT ||
           optchartype[i] == FILE_OPT )
        {
          setValue( type[0] , chomp(value) );
          return;
        }
      }
    }
  }
  /* if no char options matched */
  for( int i = 0 ; i < option_counter ; i++ ){
    if( options[i].compare(type) == 0 ){ /* match */
      if( optiontype[i] == COMMON_OPT ||
         optiontype[i] == FILE_OPT )
      {
        setValue( type , chomp(value) );
        return;
      }
    }
  }
  printVerbose( "Unknown option in resourcefile : " );
  printVerbose( type );
  printVerbose( );
}

void
AnyOption::justValue( char *type )
{
  
  if ( chomp(type).size() == 1  ){ /* this is a char option */
    for( int i = 0 ; i < optchar_counter ; i++ ){
      if(  optionchars[i] == type[0]  ){ /* match */
        if( optchartype[i] == COMMON_FLAG ||
           optchartype[i] == FILE_FLAG )
        {
          setFlagOn( type[0] );
          return;
        }
      }
    }
  }
  /* if no char options matched */
  for( int i = 0 ; i < option_counter ; i++ ){
    if( options[i].compare(type) == 0 ){ /* match */
      if( optiontype[i] == COMMON_FLAG ||
         optiontype[i] == FILE_FLAG )
      {
        setFlagOn( type );
        return;
      }
    }
  }
  printVerbose( "Unknown option in resourcefile : " );
  printVerbose( type  );
  printVerbose( );
}

/*
 * usage and help
 */


void
AnyOption::printAutoUsage()
{
  if( autousage ) printUsage();
}

void
AnyOption::printUsage()
{
  
  if( once ) {
    once = false ;
    cout << endl ;
    for( int i = 0 ; i < usage_lines ; i++ )
      cout << usage[i] << endl ;
    cout << endl ;
  }
}

void
AnyOption::addUsage( string line , bool advanced)
{
  if(!advanced){
    usage.push_back(line);
    usage_lines++;
  }
  addAdvanced(line);
}

void
AnyOption::printAdvanced()
{
  if( once ) {
    once = false ;
    cout << endl ;
    for( int i = 0 ; i < advanced_lines ; i++ )
      cout << advanced[i] << endl ;
    cout << endl ;
  }
}

void
AnyOption::addAdvanced( string line )
{
  advanced.push_back(line);
  advanced_lines++;
}

void
AnyOption::addUsageError( string line )
{
  cout << endl ;
  cout << "OPTIONS ERROR : Failed allocating extra memory " << endl ;
  cout << "While adding the usage/help  : \""<< line << "\"" << endl;
  cout << "Exiting." << endl ;
  cout << endl ;
  exit(0);
  
}


string AnyOption::operator[](const string& option_name)
{
  if (getFlag(option_name))
    return TRUE_FLAG;
  if (getValue(option_name) != NULL)
    return *getValue(option_name);
  else if (default_values.count(option_name))
    return default_values[option_name];
  else
    return "";
}

bool AnyOption::count(const string& option_name)
{
  return (getFlag(option_name) || getValue(option_name) != NULL);
}

string AnyOption::word_wrap(string sentence, int width)
{
  string::iterator it = sentence.begin();
  string::iterator last_space = sentence.begin();
  
  int accumulated_width = 0;
  while (it != sentence.end())
  {
    accumulated_width++;
    if (*it == ' ') last_space = it;
    
    if (accumulated_width > width)
    {
      // Go back to letter after space
      it = last_space;
      *last_space = '\n';
      accumulated_width = 0;
    }
    it++;
  }
  
  return sentence;
}
